# coding: utf-8
from collections import deque
from typing import Callable, Union

from PySide6.QtCore import QThread, Signal
from loguru import logger
from sqlalchemy.orm import Session

from common import signalBus
from common.database import create_session


class SqlRequest:
    """
    SqlRequest表示执行带有参数的函数的请求和接收结果的槽。
    """

    def __init__(
            self,
            func: Callable,
            args: tuple,
            kwargs: dict,
            slot: Callable,
    ):
        self.func = func
        self.args = args
        self.kwargs = kwargs
        self.slot = slot

    def __str__(self):
        return f"Request({self.func}, {self.args}, {self.kwargs}, {self.slot})"


class SqlResponse:
    """
    SqlResponse表示执行SqlRequest的结果。
    """

    def __init__(
            self,
            slot: Callable = None,
            result: object = None,
            error: Union[Exception, str, None] = None,
    ):
        self.slot = slot
        self.result = result
        self.error = error

    def __str__(self):
        return f"Response({self.slot}, {self.result}, {self.error})"


def send_sql_request(func: Callable, *args, slot: Callable = None, **kwargs):
    """
    发送SqlRequest请求。
    """
    request = SqlRequest(func, args, kwargs, slot=slot)
    signalBus.dbSendSig.emit(request)


class DbThread(QThread):
    failed = Signal(object)

    def __init__(self, parent=None):
        super().__init__(parent)
        self.queue = deque()
        self.session: Session = create_session()
        signalBus.dbSendSig.connect(self.addTask)

    def run(self):
        # 运行任务
        while self.queue:
            request: SqlRequest = self.queue.popleft()
            logger.debug(f"运行任务: {request}")
            try:
                result = request.func(*request.args, **request.kwargs, session=self.session)
                error = None
            except Exception as e:
                result = None
                error = str(e)
                logger.error(f"任务运行错误: {e}")
                self.failed.emit(error)
            response = SqlResponse(request.slot, result, error)
            logger.debug(f"任务完成了，发送结果: {response}")
            signalBus.dbResultSig.emit(response)
        self.session.close()

    def addTask(self, task: Callable):
        self.queue.append(task)
        if not self.isRunning():
            self.start()
